//: [Previous](@previous)

import Foundation
import Darwin

//创建枚举类型
enum TextAlignment {
    case left
    case right
    case center
}

//创建枚举实例
var alignment = TextAlignment.left

//修改枚举值
alignment = .right


//使用switch处理枚举值
switch alignment{
case .left:
    print("left aligned")
case .right:
    print("right aligned")
case .center:
    print("center aligned")
}

//原始值枚举
//默认原始值是从0开始,逐个递增
enum TextAlignment1:Int {
    case left
    case right
    case center
}
let alignment1 = TextAlignment1.left
print("\(alignment1) has raw value \(alignment1.rawValue)")

//指定原始值
enum TextAlignment2:Int {
    case left = 10
    case right = 20
    case center = 30
}

//通过原始值创建一个枚举实例
let rawValue = 20
if let alignment2 = TextAlignment2(rawValue:rawValue){
    print("通过原始值创建的枚举实例是:\(alignment2)")
}else{
    print("通过原始值创建的枚举实例失败")
}

//使用string类型做原始值的枚举类型
//如果不为每一个成员指定原始值字符串,那么会默认使用成员本身的名字作为原始值,所以删除后边的原始值字符串,效果是一样的
enum ProgrammingLanguage:String {
    case swift = "swfit"
    case objectiveC = "objective-c"
    case c = "c"
    case cpp = "c++"
    case java = "java"
}


let myFavoriteLanguage = ProgrammingLanguage.swift
print("我最喜欢的编程语言是:\(myFavoriteLanguage)")

//枚举的方法
enum Lightbulb {
    case on
    case off
    
    func surfaceTemperature(forAmbientTemperature ambient:Double) -> Double{
        switch self{
        case .on:
            return ambient + 150
        case .off:
            return ambient
        }
    }
    
    //因为枚举是值类型,不能再方法内对self进行修改
    //如果希望值类型的方法能修改self,需要标记这个方法是mutating
    mutating func toggle(){
        switch self {
        case .on:
            self = .off
        case .off:
            self = .on
        }
    }
}

var bulb = Lightbulb.on
let ambientTemperature = 77.0
var bulbTemperature = bulb.surfaceTemperature(forAmbientTemperature:ambientTemperature)
print("灯泡的温度是:\(bulbTemperature)")

bulb.toggle()
bulbTemperature = bulb.surfaceTemperature(forAmbientTemperature:ambientTemperature)
print("灯泡的温度是:\(bulbTemperature)")


//关联值
enum ShapeDimensions {
    //没有关联值,因为点没有尺寸
    case point
    //正方形的关联值是边长
    case square(side:Double)
    //长方形的关联值是宽和高
    case rectangle(width:Double,height:Double)
    //直角三角形
    case rightTriangle(width1:Double,width2:Double,width3:Double)
    
    //计算图形面积的方法
    func area() -> Double {
        switch self {
        case let .square(side:side):
            return side * side
        case let .rectangle(width:w,height:h):
            return w * h
        case let .point:
            return 0
        case let .rightTriangle(w1,w2,w3):
            return w1 * w2 / 2
        }
    }
    
    //练习1:
    //增加一个计算周长的方法
    func perimeter() -> Double{
        switch self {
        case let .square(side:side):
            return side * 4
        case let .rectangle(width:w,height:h):
            return (w + h) * 2
        case let .point:
            return 0
        case let .rightTriangle(w1,w2,w3):
            return w1 + w2 + w3
        }
    }
}

//要创建ShapeDimensions实例,必须指定成员和相应的关联值
var squareShare = ShapeDimensions.square(side:10.0)
var rectShape = ShapeDimensions.rectangle(width:5.0,height:10.0)
var pointShape = ShapeDimensions.point

print("square`s area = \(squareShare.area())")
print("rectangle`s area = \(rectShape.area())")
print("point`s area = \(pointShape.area())")


print("正方形的周长是:\(squareShare.perimeter())")
print("长方形的周长是:\(rectShape.perimeter())")
print("点的周长是:\(pointShape.perimeter())")

//递归枚举
//枚举的成员值,指向同类型的枚举实例,就可能导致一个无限大的枚举实例
//如果有一个无限大的枚举实例,那么编译器无法知道这个枚举实例的内存占用大小
//使用关键字:indirect 标记枚举类型,就可以,解决这个问题,这个关键字的意思是
//将枚举实例,指向一个指针.
//也可以不给整个枚举类型使用关键字indirect,也可以把递归的成员单独标记indirect
enum FamilyTree {
    case noKnowParents
    indirect case oneKnownParent(name:String,ancerstors:FamilyTree)
    indirect case twoKnownParents(fatherName:String,
                                 fatherAncestors:FamilyTree,
                                 motherName:String,
                                 motherAncestors:FamilyTree)
}

//创建一个递归枚举实例
let fredAncestors = FamilyTree.twoKnownParents(fatherName:"Fred Sr.",
                                               fatherAncestors:.oneKnownParent(name:"Beth",
                                                                               ancerstors:.noKnowParents),
                                               motherName:"Marsha",
                                               motherAncestors:.noKnowParents)
print(fredAncestors)
